home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Prog / S / SurferPlus / surferplus.p < prev    next >
Encoding:
Text File  |  1990-09-27  |  43.3 KB  |  1,735 lines  |  [TEXT/MPS ]

  1. {------------------------------------------------------------------------------
  2. #
  3. #    Apple Products Presents
  4. #
  5. #    S U R F E R    ----- A CommToolbox Sample Application
  6. #        by Alex Kazim
  7. #    SURFERPLUS
  8. #        by Mary Chan
  9. #
  10. #    Based on the MacDTS Simple Sample Application
  11. #
  12. #    SurferPlus.p    -    Pascal Source
  13. #
  14. #    Copyright © 1988-9 Apple Computer, Inc.
  15. #    All rights reserved.
  16. #
  17. #    Versions:    Sample 1.0                    08/88
  18. #                Sample 1.01                    11/88
  19. #
  20. #                Surfer 1.0                    10/89
  21. #                SurferPlus 1.0                9/17
  22. ------------------------------------------------------------------------------}
  23.  
  24. {
  25. MODIFICATION HISTORY
  26.     8/16/90        MC        • added scroll back proc
  27.  
  28.     9/26/89        kaz        • changed case on constants to match documentation
  29.                         • Fixed error handling to only call xxEvent() if the
  30.                         target of the event is a tool window
  31.                         • Initializes gBuffer according to sizes[cmDataIn]
  32.                         after the CMNew call
  33.                         
  34.     10/1/89        kaz        • TermGetConnEnvirons() and FTGetConnEnvirons() were
  35.                         merged into one routine: ToolGetConnEnvirons()
  36.                         • IsAppWindow() uses GetWRefCon instead of looking
  37.                         at the windowrecord refcon field.
  38.                         • Moved DiposePtr(gBuffer) to CloseWindow
  39.                         • HLock/HUnlock all the tool handles
  40.                         • Took out alerts to let the tools handle it themselves
  41.                         
  42.     10/4/89        kaz        • Was forgetting to clear gStartFT after a receive
  43.     9/90        MC        • scroll back cache and selection support
  44.     
  45. }
  46.  
  47. PROGRAM Sample;
  48.  
  49. USES
  50.     MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf,
  51.     CTBUtils, FTIntf,CMIntf,TMIntf, CRMIntf;
  52.  
  53. CONST
  54.     _WaitNextEvent                = $A860;
  55.     _UnimplementedToolTrap        = $A89F;
  56.     _CommToolboxTrap            = $8B;
  57.     _UnimplementedOSTrap        = $9F;
  58.  
  59.     kSysEnvironsVersion        = 1;
  60.  
  61.     kOSEvent                = app4Evt;    { event used by MultiFinder    }
  62.     kSuspendResumeMessage    = 1;        { high byte of suspend/resume event message}
  63.     kResumeMask                = 1;        { bit of message field for resume vs. suspend}
  64.      
  65.     kMinHeap    = 150 * 1024; 
  66.     kMinSpace    = 10 * 1024;
  67.     kBufferSize    = 1 * 1024;                { Data Storage Size = 1K    }
  68.     
  69.     kExtremeNeg    = -32768;
  70.     kExtremePos    = 32767 - 1;            { required for old region bug    }
  71.     
  72.     kDefaultTermTool    = 'VT102';        { what tools we want first        }
  73.     kDefaultFTTool        = 'Text';
  74.     kDefaultConnTool    = 'Serial';
  75.     
  76.     rMenuBar    = 128;                    { application's menu bar    }
  77.     rAboutAlert    = 128;                    { about alert                }
  78.     rUserAlert    = 129;                    { error user alert            }
  79.     rWindow        = 128;                    { application's window        }
  80.  
  81.     mApple            = 128;                    {Apple menu}
  82.     iAbout            = 1;
  83.  
  84.     mFile            = 129;                    {File menu}
  85.     iNew            = 1;
  86.     iOpen            = 2;
  87.     iClose            = 4;
  88.     iSendFile        = 9;
  89.     iReceiveFile    = 10;
  90.     iQuit            = 15;
  91.  
  92.     mEdit            = 130;                    {Edit menu}
  93.     iUndo            = 1;
  94.     iCut            = 3;
  95.     iCopy            = 4;
  96.     iPaste            = 5;
  97.     iClear            = 6;
  98.  
  99.     mSettings        = 131;                    {Settings menu}
  100.     iConnection        = 1;
  101.     iFileTransfer    = 2;
  102.     iTerminal        = 3;
  103.     
  104.     kDITop        = $0050;
  105.     kDILeft        = $0070;
  106.  
  107.  
  108.     VERTSCROLLID = 128;                        { vertical scroll bar resource ID }
  109.     HORISCROLLID = 129;                        { horizontal scroll bar resource ID }
  110.     
  111.     MAXCACHECOL     = 132;                    { cache column }
  112.     MINCACHECOL        = 80;
  113.     MAXCACHELINE    = 24;                    { cache row    }
  114.     CACHESIZE        = 24*132;                { total cache size }
  115.     GROWMINHLIMIT    = 50;                    { size window limit }
  116.     GROWMINVLIMIT    = 50;                    { size window limit }
  117.     
  118.  
  119. VAR
  120.     gHasWaitNextEvent    : BOOLEAN;        {set up by Initialize}
  121.     gInBackground        : BOOLEAN;        {maintained by Initialize and DoEvent    }
  122.  
  123.     gStopped            : BOOLEAN;        {maintained by Initialize and SetLight    }
  124.     
  125.     gConn                : ConnHandle;
  126.     gFT                    : FTHandle;
  127.  
  128.     gBuffer                : Ptr;            { Data Storage for Reads/Writes            }
  129.     
  130.     gFTSearchRefNum        : LONGINT;        { Auto-Initiate File Transfers            }
  131.     gStartFT            : BOOLEAN;        { Auto-start                            }
  132.     gWasFT                : BOOLEAN;        { In progress                            }
  133.  
  134. {$Z+}
  135.     _GTERM                : TermHandle;    { Tool Handles: Single Session            }
  136.     _MYDATAHANDLE        : Handle;
  137.     _MYDATASIZE            : LONGINT;
  138.     _VERTSCROLLHDL        : ControlHandle;
  139.     _HORISCROLLHDL        : ControlHandle;
  140.     _TERMVISRECT            : Rect;
  141.     _UPDATERGN            : RgnHandle;                { preallocated update rgn hdl for scrolling }
  142.     _CACHEDESTRECT        : Rect;                        { cache destination rect }
  143.     _MYDATAHDL            : Handle;                    { preallocate handle for TMPaint }
  144.     _GROWRECT            : Rect;                        { size window limit }
  145.     _PORTRECT            : Rect;                        { current window PORTRECT }
  146.     _BLANKLINE            : PACKED ARRAY[MINCACHECOL..MAXCACHECOL] OF CHAR;
  147.     _OLDRGN                : RgnHandle;
  148.     _NEWRGN                : RgnHandle;
  149.     _SAVECLIP            : RgnHandle;
  150. {$Z-}
  151.  
  152. PROCEDURE AlertUser(msg: Str255; fatal: BOOLEAN); FORWARD;
  153. PROCEDURE Terminate; FORWARD;
  154. FUNCTION MyCacheProc( refcon : LONGINT; theTermData : TermDataBlock ) : LONGINT; EXTERNAL;
  155. FUNCTION MyClickProc( refcon : LONGINT ) : LONGINT; EXTERNAL;
  156. PROCEDURE HandleMouseDown ( window : WindowPtr; VAR  event : EventRecord); C;EXTERNAL;
  157. PROCEDURE DoSizeWindow( window : WindowPtr; VAR  event : EventRecord);C;EXTERNAL;
  158. PROCEDURE UpdateCache( _UPDATERGN: RgnHandle);C;EXTERNAL;
  159. PROCEDURE SetVScrollMax;C;EXTERNAL;
  160. PROCEDURE CheckTermEnv( GetIt: Boolean);C;EXTERNAL;
  161. PROCEDURE DeSelection;C;EXTERNAL;
  162. PROCEDURE CacheActivate( theWindow: WindowPtr; becomingActive : Boolean);C;EXTERNAL;
  163.  
  164. { ******************************************************************
  165. *    TrapAvailable    - Checks to see if a given trap is implemented
  166. *
  167. *        tNumber        - trap number
  168. *        tType        - type of trap
  169. *
  170. *        returns        - true if it exists
  171. *
  172. ********************************************************************* }
  173. {$S Initialize}
  174. FUNCTION TrapAvailable(tNumber: INTEGER; tType: TrapType): BOOLEAN;
  175. VAR
  176.     unImplemented    : INTEGER;
  177.     
  178. BEGIN
  179.     IF tType = OSTrap THEN
  180.         unImplemented := _UnimplementedOSTrap
  181.     ELSE
  182.         unImplemented := _UnimplementedToolTrap;
  183.  
  184.     TrapAvailable := NGetTrapAddress(tNumber, tType) <> GetTrapAddress(unImplemented);
  185. END; {TrapAvailable}
  186.  
  187.  
  188. { ******************************************************************
  189. *    TermSendProc    - Sends the data out the connection
  190. *
  191. *        thePtr        - the data to send
  192. *        theSize        - bytes to send
  193. *        refcon        - terminal tool refcon
  194. *        flags        - connection flags
  195. *
  196. *        returns        - bytes sent
  197. *
  198. ********************************************************************* }
  199. {$S Main}
  200. FUNCTION TermSendProc(thePtr: Ptr;theSize: LONGINT;
  201.                     refcon: LONGINT;flags: INTEGER): LONGINT;
  202. VAR
  203.     theErr        : CMErr;
  204.     
  205. BEGIN
  206.     TermSendProc := 0;                        { Assume the worst            }
  207.     
  208.     IF gConn <> NIL THEN BEGIN    
  209.     
  210.         { DO NOT check to see if the conn is first open before sending    }
  211.         { as the tool might be directly interpreting the data            }
  212.  
  213.         theErr := CMWrite(gConn,thePtr,theSize,
  214.                             cmData,FALSE,NIL,0,flags);
  215.                             
  216.         IF (theErr = noErr) THEN
  217.             TermSendProc := theSize;        { If ok, we sent all        }
  218.         
  219.     END; { Good Connection    }
  220.     
  221. END; { TermSendProc        }
  222.  
  223.  
  224.  
  225. { ******************************************************************
  226. *    TermRecvProc    - Gets the data from the connection and sends 
  227. *                    it to the terminal tool.
  228. *
  229. *        NOTE        - This is NOT a callback proc, but does 
  230. *                    resemble the functionality.
  231. *
  232. *
  233. ********************************************************************* }
  234. {$S Main}
  235. PROCEDURE TermRecvProc;
  236. VAR
  237.     theErr        : CMErr;        { Any errors            }
  238.     status        : CMStatFlags;    { For the conn tool        }
  239.     sizes        : CMBufferSizes;
  240.     flags        : INTEGER;
  241.     err            : TMErr;
  242.     
  243. BEGIN
  244.     IF (gConn <> NIL) AND (_GTERM <> NIL) THEN BEGIN
  245.     
  246.         { Get the state of the connection    }
  247.         theErr := CMStatus(gConn, sizes, status);
  248.         
  249.         IF (theErr = noErr) THEN  BEGIN
  250.         
  251.             { Route the data if we have any            }
  252.             IF (BAND(status, cmStatusOpen + cmStatusDataAvail) <> 0) AND 
  253.                                     (sizes[cmDataIn] <> 0) THEN BEGIN
  254.                 
  255.                 { Don't overflow my buffer        }
  256.                 IF sizes[cmDataIn] > kBufferSize THEN
  257.                     sizes[cmDataIn] := kBufferSize;
  258.             
  259.                 { Tell the tool to get the data    }
  260.                 theErr := CMRead(gConn, gBuffer, sizes[cmDataIn],
  261.                                         cmData, FALSE,NIL,0,flags);
  262.                 
  263.                 { Send data to the terminal    }
  264.                 IF (theErr = noErr) THEN
  265.                 BEGIN
  266.                     sizes[cmDataIn] := TMStream(_GTERM,gBuffer,
  267.                                             sizes[cmDataIn],flags);
  268.                     CheckTermEnv( FALSE);
  269.                         
  270.                 END;
  271.                                             
  272.             END; { sizes <> 0    }
  273.                 
  274.         END; { Good Status        }
  275.         
  276.         IF (theErr <> noErr) THEN
  277.             ;        { Connection tool will alert the user on an error    }
  278.         
  279.     END; { Good term & conn    }
  280.  
  281. END; { TermRecvProc        }
  282.  
  283.  
  284.  
  285. { ******************************************************************
  286. *    ToolGetConnEnvirons    - Gets the connection environs for
  287. *                        the FT or Term tool
  288. *
  289. *        refCon            - the tool refcon
  290. *        theEnvirons        - the environment
  291. *
  292. *        returns            - an environment error
  293. *
  294. ********************************************************************* }
  295. {$S Main}
  296. FUNCTION ToolGetConnEnvirons(refCon: LONGINT;
  297.                     VAR theEnvirons: ConnEnvironRec): OSErr;
  298. BEGIN
  299. ToolGetConnEnvirons := envNotPresent;        { pessimism         }
  300.  
  301. { Version is set by the tool    }
  302. IF (gConn <> NIL) THEN
  303.     ToolGetConnEnvirons := CMGetConnEnvirons(gConn,theEnvirons);
  304.  
  305. END; { TermGetConnEnvirons    }
  306.  
  307.  
  308.  
  309. { ******************************************************************
  310. *    FTSendProc    - Sends data during a file transfer
  311. *
  312. *        thePtr        - data to send
  313. *        theSize        - bytes to send
  314. *        refcon        - the FTtool refcon
  315. *        channel        - which channel to use
  316. *        flags        - connection flags
  317. *
  318. *        returns        - bytes sent
  319. *
  320. ********************************************************************* }
  321. {$S Main}
  322. FUNCTION FTSendProc(thePtr: Ptr;theSize: LONGINT;refcon: LONGINT;
  323.                     channel: CMChannel;flags: INTEGER) : LONGINT;
  324. VAR
  325. theErr : CMErr;
  326.  
  327. BEGIN
  328. FTSendProc := 0;                    { Assume the worst        }
  329.  
  330. IF gConn <> NIL THEN BEGIN
  331.                                     { Send the data            }
  332.     theErr := CMWrite(gConn,thePtr,theSize,channel, 
  333.                                     FALSE, NIL, 0, flags);
  334.     IF (theErr = noErr) THEN
  335.         FTSendProc := theSize;        { if ok, we sent all    }
  336.  
  337. END; { Good Connection    }
  338.  
  339. END; { FTSendProc    }
  340.  
  341.  
  342.  
  343. { ******************************************************************
  344. *    FTReceiveProc    - Gets data during a file transfer
  345. *
  346. *        thePtr        - place for data
  347. *        theSize        - bytes to get
  348. *        refcon        - the FTtool refcon
  349. *        channel        - which channel to use
  350. *        flags        - connection flags
  351. *
  352. *        returns        - bytes gotten
  353. *
  354. ********************************************************************* }
  355. {$S Main}
  356. FUNCTION FTReceiveProc(thePtr: Ptr;theSize: LONGINT;refcon: LONGINT; 
  357.                             channel: CMChannel;VAR flags: INTEGER): LONGINT;
  358. VAR
  359. theErr : CMErr;
  360.  
  361. BEGIN
  362. FTReceiveProc := 0;                    { Assume the worst        }
  363.  
  364. IF gConn <> NIL THEN BEGIN
  365.                                     { Read all the data        }
  366.     theErr := CMRead(gConn,thePtr,theSize, 
  367.                                     channel,FALSE,NIL,0,flags);
  368.     IF (theErr = noErr) THEN
  369.         FTReceiveProc := theSize;    { if ok, we got all        }
  370.  
  371. END; { Good Connection    }
  372.  
  373. END; { FTReceiveProc    }
  374.  
  375.  
  376. { ******************************************************************
  377. *    AutoRecCallback    - Sets the file transfer flag if a auto-
  378. *                    receive string was found.
  379. *
  380. *        theConn            - which connection tool found it
  381. *        data            - ptr to last character in the match
  382. *        refNum            - which search was found
  383. *
  384. ********************************************************************* }
  385. {$S Main}
  386. PROCEDURE AutoRecCallback(theConn: ConnHandle; data: Ptr; refNum: LONGINT);
  387. BEGIN
  388. { We can't call FTStart() or CMRemoveSearch() here as     }
  389. { this proc might be called from Interrupt level        }
  390.  
  391. IF (gFTSearchRefNum = refNum) THEN
  392.     gStartFT := TRUE;        { Set the flag to call FTStart in Idle    }
  393. END; { AutoRecCallBack    }
  394.  
  395.  
  396.  
  397. { ******************************************************************
  398. *    AddFTSearch        - Checks to see if the file transfer has an
  399. *                    auto-receive string, and adds a search to 
  400. *                    find it.
  401. *
  402. ********************************************************************* }
  403. {$S Main}
  404. PROCEDURE AddFTSearch;
  405. VAR
  406. tempStr        : Str255;            { the string to look for    }
  407.  
  408. BEGIN    
  409. IF (gFT <> NIL) AND (gConn <> NIL) THEN BEGIN
  410.     tempStr := gFT^^.AutoRec;        { Do I need to add a search        }
  411.     
  412.     IF (tempStr <> '') THEN BEGIN
  413.         gFTSearchRefNum := CMAddSearch(gConn,tempStr,cmSearchSevenBit,
  414.                                                         @AutoRecCallback);
  415.         IF gFTSearchRefNum = -1 THEN BEGIN
  416.             AlertUser('Couldn''t add stream search',FALSE);
  417.             gFTSearchRefNum := 0;
  418.         END;
  419.     END; { can autoreceive    }
  420.     
  421. END; { good FT and Conn    }
  422.  
  423. END; { AddFTSearch        }
  424.  
  425.  
  426.  
  427. { ******************************************************************
  428. *    DoSend    - Initiates a File Transfer send from the menu command
  429. *
  430. ********************************************************************* }
  431. {$S Main}
  432. PROCEDURE DoSend;
  433. VAR
  434. theReply    : SFReply;            { File Info                    }
  435. where        : Point;            { Top Left of File dialog    }
  436. numTypes    : INTEGER;            { File Types to display        }
  437. typeList    : SFTypeList;
  438. anyErr        : FTErr;            { Error handler                }
  439.  
  440. BEGIN
  441. IF gFT <> NIL THEN BEGIN
  442.     SetPt(where, 100, 100);
  443.     
  444.     { If the FT tool can only send Text files, then            }
  445.     { only display text files, else display all types        }
  446.  
  447.     { Check to see if Text Only flag is set    }
  448.     IF BAND(gFT^^.attributes, ftTextOnly) <> 0 THEN BEGIN
  449.         typeList[0] := 'TEXT';
  450.         numTypes := 1;
  451.     END
  452.     ELSE
  453.         numTypes := -1;
  454.         
  455.     SFGetFile(where, 'File to Send', NIL, numTypes,
  456.                                     typeList, NIL, theReply);
  457.     
  458.     { Did the user hit OK or Cancel    }
  459.     IF theReply.good THEN BEGIN
  460.         { Transfer the file TO the remote    }
  461.         anyErr := FTStart(gFT,ftTransmitting,theReply);
  462.         
  463.         IF (anyErr <> noErr) THEN
  464.             ;            { File Transfer tool will alert user on an error    }
  465.             
  466.     END; { Good file    }
  467. END; { Good FTHandle    }
  468.  
  469. END; { DoSend    }
  470.  
  471.  
  472. { ******************************************************************
  473. *    DoReceive    - Initiates a File Transfer receive from the menu
  474. *
  475. ********************************************************************* }
  476. {$S Main}
  477. PROCEDURE DoReceive;
  478. VAR
  479. theReply        : SFReply;        { File Info            }
  480. anyErr            : OSErr;        { Errors on Start    }
  481.  
  482. BEGIN
  483. IF gFT <> NIL THEN BEGIN
  484.     
  485.     { Let the FT tool use its own default file info    }
  486.     theReply.vRefNum := 0;
  487.     theReply.fName := '';
  488.     
  489.     gStartFT := FALSE;        { Shut the flag down            }
  490.     
  491.     { We remove the search temporarily in case it comes        }
  492.     { across during the transfer. Will be re-added in the    }
  493.     { idle loop once the transfer is completed                }
  494.     
  495.     IF gConn <> NIL THEN
  496.         IF (gFT^^.autoRec <> '') AND (gFTSearchRefNum <> 0) THEN BEGIN
  497.             CMRemoveSearch(gConn, gFTSearchRefNum);
  498.             gFTSearchRefNum := 0;    { We found it already    }
  499.         END;
  500.     
  501.     { Start receiving the file                        }
  502.     { The rest gets transferred in the Idle loop    }
  503.     
  504.     anyErr := FTStart(gFT,ftReceiving,theReply);
  505.     
  506.     IF (anyErr <> noErr) THEN
  507.         ;            { File Transfer tool will alert user on an error    }
  508.         
  509. END; { Good Handle    }
  510.  
  511. END; { DoReceive    }
  512.  
  513.  
  514. { ******************************************************************
  515. *    IsDAWindow    - Checks to see if a window belongs to a desk acc.
  516. *
  517. *        window        - the culprit
  518. *
  519. *        returns        - true if it's a DA
  520. *
  521. ********************************************************************* }
  522. {$S Main}
  523. FUNCTION IsDAWindow(window: WindowPtr): BOOLEAN;
  524.  
  525. {Check if a window belongs to a desk accessory.}
  526.  
  527. BEGIN
  528. IF window = NIL THEN
  529.     IsDAWindow := FALSE
  530. ELSE    {DA windows have negative windowKinds}
  531.     IsDAWindow := WindowPeek(window)^.windowKind < 0;
  532. END; {IsDAWindow}
  533.  
  534.  
  535.  
  536. { ******************************************************************
  537. *    IsAppWindow    - Checks to see if a window belongs to our app
  538. *
  539. *        window        - the culprit
  540. *
  541. *        returns        - true if it's an app window
  542. *
  543. ********************************************************************* }
  544. {$S Main}
  545. FUNCTION IsAppWindow(window: WindowPtr): BOOLEAN;
  546. VAR
  547. theRefCon        : LONGINT;
  548.  
  549. BEGIN
  550. { Check the userkind and the refcon for tool windows}
  551. IF window = NIL THEN
  552.     IsAppWindow := FALSE
  553. ELSE BEGIN
  554.     theRefCon := GetWRefCon(window);
  555.     WITH WindowPeek(window)^ DO
  556.         IsAppWindow := ((windowKind >= userKind) | (windowKind = dialogKind)) &
  557.                             (_GTERM <> TermHandle(theRefCon)) &
  558.                             (gConn <> ConnHandle(theRefCon)) &
  559.                             (gFT <> FTHandle(theRefCon));
  560. END;
  561. END; {IsAppWindow}
  562.  
  563.  
  564.  
  565. { ******************************************************************
  566. *    AlertUser    - Informs the user of any errors
  567. *
  568. *        msg        - The string to display
  569. *        fatal    - Exit if this is a fatal error
  570. *
  571. ********************************************************************* }
  572. {$S Main}
  573. PROCEDURE AlertUser(msg: Str255; fatal: BOOLEAN); 
  574. VAR
  575. itemHit    : INTEGER;
  576.  
  577. BEGIN
  578. SetCursor(arrow);
  579.  
  580. ParamText(msg,'','','');
  581. itemHit := Alert(rUserAlert, NIL);
  582.  
  583. IF fatal THEN
  584.     Terminate;
  585. END; { AlertUser    }
  586.  
  587.  
  588.  
  589. { ******************************************************************
  590. *    OpenConnection    - Initiates a connection
  591. *
  592. ********************************************************************* }
  593. {$S Main}
  594. PROCEDURE OpenConnection; 
  595. VAR
  596. theErr    : CMErr;
  597. sizes    : CMBufferSizes;        { Connection Tool data        }
  598. status    : CMStatFlags;
  599.  
  600. BEGIN
  601. IF (gConn <> NIL) THEN BEGIN
  602.  
  603.     { Get connection info        }
  604.     theErr := CMStatus(gConn, sizes, status);
  605.     
  606.     { If it isn't already open, then open it    }
  607.     IF (theErr = noErr) THEN
  608.         IF BAND(status, cmStatusOpen + cmStatusOpening) = 0 THEN
  609.             theErr := CMOpen(gConn, FALSE, NIL, -1);
  610.     
  611.     IF (theErr <> noErr) THEN
  612.         ;            { Conn tool will alert user on an error        }
  613. END;
  614. END; {OpenConnection}
  615.  
  616.  
  617.  
  618. { ******************************************************************
  619. *    CloseConnection    - Kills a connection
  620. *
  621. ********************************************************************* }
  622. {$S Main}
  623. PROCEDURE CloseConnection; 
  624. VAR
  625. theErr    : CMErr;
  626. sizes    : CMBufferSizes;        { Connection Tool data        }
  627. status    : CMStatFlags;
  628.  
  629. BEGIN
  630. { Kill the current connection    }
  631. IF (gConn <> NIL) THEN BEGIN
  632.     theErr := CMStatus(gConn, sizes, status);
  633.     
  634.     { If it's open, then close it    }
  635.     IF (theErr = noErr) THEN
  636.         IF BAND(status, cmStatusOpen + cmStatusOpening) <> 0 THEN
  637.             theErr := CMClose(gConn, FALSE, NIL, 0, TRUE);
  638.     
  639.     IF (theErr <> noErr) THEN
  640.         ;        { Conn tool will alert user on an error        }
  641. END;
  642.  
  643. END; {CloseConnection}
  644.  
  645.  
  646.  
  647. { ******************************************************************
  648. *    DoCloseWindow    - Closes the window
  649. *
  650. *        window        - the culprit
  651. *
  652. *        returns        - always returns true
  653. *
  654. ********************************************************************* }
  655. {$S Main}
  656. FUNCTION DoCloseWindow(window: WindowPtr): BOOLEAN;
  657. BEGIN
  658. DoCloseWindow := TRUE;
  659.  
  660. IF IsDAWindow(window) THEN
  661.     CloseDeskAcc(WindowPeek(window)^.windowKind)
  662. ELSE IF IsAppWindow(window) THEN BEGIN
  663.  
  664.     CloseConnection;            { Stop what we're doin'        }
  665.     
  666.     IF _GTERM <> NIL THEN BEGIN    { Dispose of all the tools    }
  667.         HUnlock(Handle(_GTERM));
  668.         TMDispose(_GTERM);
  669.     END;
  670.     
  671.     IF gFT <> NIL THEN BEGIN
  672.         HUnlock(Handle(gFT));
  673.         FTDispose(gFT);
  674.     END;
  675.         
  676.     IF (gConn <> NIL) THEN BEGIN
  677.         HUnlock(Handle(gConn));
  678.         CMDispose(gConn);
  679.     END;
  680.             
  681.     IF (gBuffer <> NIL) THEN    { Clean up our buffer        }
  682.         DisposPtr(gBuffer);
  683.         
  684.     { dispose the cache data handle }
  685.     DisposHandle( _MYDATAHANDLE );
  686.     DisposHandle( _MYDATAHDL );
  687.     { dispose the update region }
  688.     DisposeRgn( _UPDATERGN );
  689.     { dispose the selectin region }
  690.     DisposeRgn( _OLDRGN );
  691.     DisposeRgn( _NEWRGN );
  692.     DisposeRgn( _SAVECLIP );
  693.  
  694.     DisposeWindow(window);
  695. END; { App Window    }
  696.  
  697. END; {DoCloseWindow}
  698.  
  699.  
  700. { ******************************************************************
  701. *    FindToolID    - Tries to get the default tool proc id,
  702. *                otherwise, gets the first one it finds.
  703. *
  704. *        toolClass    - What kind of tool: term, ft, conn
  705. *
  706. *        returns        - the tool proc id or -1 if not found
  707. *
  708. ********************************************************************* }
  709. {$S Main}
  710. FUNCTION FindToolID(toolClass: OSType): INTEGER;
  711. VAR
  712. toolName    : Str255;        { tool file name        }
  713. anyErr        : OSErr;
  714. procID        : INTEGER;        { tool fref number        }
  715.  
  716. BEGIN
  717. procID := -1;                { Unknown tool            }
  718.  
  719. IF (toolClass = ClassTM) THEN BEGIN
  720.     { If it can't get the default, get the 1st    }
  721.     toolName := kDefaultTermTool;
  722.     procID := TMGetProcID(toolName);
  723.     
  724.     IF (procID = -1) THEN BEGIN
  725.         anyErr := CRMGetIndToolName(toolClass,1,toolName);
  726.         IF (anyErr = noErr) THEN
  727.             procID := TMGetProcID(toolName);
  728.     END;
  729.     
  730. END { ClassTM}
  731.  
  732. ELSE IF (toolClass = ClassCM) THEN BEGIN
  733.     { If it can't get the default, get the 1st    }
  734.     toolName := kDefaultConnTool;
  735.     procID := CMGetProcID(toolName);
  736.     
  737.     IF (procID = -1) THEN BEGIN
  738.         anyErr := CRMGetIndToolName(toolClass,1,toolName);
  739.         IF (anyErr = noErr) THEN
  740.             procID := CMGetProcID(toolName);
  741.     END;
  742.     
  743. END { ClassCM}
  744.     
  745. ELSE IF (toolClass = ClassFT) THEN BEGIN
  746.     { If it can't get the default, get the 1st    }
  747.     toolName := kDefaultFTTool;
  748.     procID := FTGetProcID(toolName);
  749.     
  750.     IF (procID = -1) THEN BEGIN
  751.         anyErr := CRMGetIndToolName(toolClass,1,toolName);
  752.         IF (anyErr = noErr) THEN
  753.             procID := FTGetProcID(toolName);
  754.     END;
  755.     
  756. END; { ClassFT}
  757.  
  758. FindToolID := procID;
  759.     
  760. END; {FindToolID}
  761.  
  762.  
  763. { ******************************************************************
  764. *    DoNewWindow    - Gets the window and creates the session
  765. *
  766. *        window        - the culprit
  767. *
  768. *        returns        - always returns true
  769. *
  770. ********************************************************************* }
  771. {$S Main}
  772. FUNCTION DoNewWindow: BOOLEAN;
  773. VAR
  774. window        : WindowPtr;    { the window to create            }
  775. theRect        : Rect;            { for the terminal bounds        }
  776. procID        : INTEGER;        { tool's ref number                }
  777. sizes        : CMBufferSizes;    { requested size of the buffers    }
  778. err            : TMErr;
  779.  
  780. BEGIN
  781. { Get window                        }
  782. window := GetNewWindow(rWindow, NIL, WindowPtr(-1));
  783.  
  784. SetPort(window);    
  785.  
  786. { TERMINAL TOOL    }
  787. procID := FindToolID(ClassTM);
  788. IF (procID = -1) THEN
  789.     AlertUser('No terminal tools found',TRUE);
  790.     
  791.  
  792. { surfer 1.1 changes starts }
  793. _HORISCROLLHDL := GetNewControl( HORISCROLLID, window);
  794. _VERTSCROLLHDL := GetNewControl( VERTSCROLLID, window);
  795.  
  796. theRect := window^.PORTRECT;
  797. With theRect Do BEGIN
  798.     SetRect( _PORTRECT, left, top, right, bottom );
  799.     right := right - 15;
  800.     bottom := bottom - 15;
  801. END;
  802.  
  803. { No cache, breakproc, or clikloop    }
  804. _GTERM := TMNew(theRect,theRect,TMSaveBeforeClear,procID,window, 
  805.                     @TermSendProc,@MyCacheProc,NIL,@MyClickProc,@ToolGetConnEnvirons,0,0);
  806.                     
  807. { surfer 1.1 changes ends }
  808.  
  809. IF _GTERM = NIL THEN
  810.     AlertUser('Can''t create a terminal tool',TRUE);
  811.  
  812. { start surfer 1.1 changes }
  813.  
  814. _OLDRGN := NewRgn;
  815. _NEWRGN := NewRgn;
  816. _SAVECLIP := NewRgn;
  817.  
  818. SetRect( _GROWRECT, GROWMINHLIMIT, GROWMINVLIMIT, 
  819.           screenBits.bounds.right, screenBits.bounds.bottom );
  820. SetRect( _CACHEDESTRECT, _GTERM^^.termRect.left, 0, 0, 0 );
  821.  
  822. { get new environment }
  823. CheckTermEnv( TRUE );
  824. With _GTERM^^.termRect Do BEGIN
  825.     SetRect( _TERMVISRECT, left, top, right, bottom );
  826. END;
  827.  
  828. { preallocate the update region for scrolling}
  829. _UPDATERGN := NewRgn;
  830. { preallocate handle for TMPaint }
  831. _MYDATAHDL := NewHandle(MAXCACHECOL);
  832.  
  833. { end surfer 1.1 changes }
  834.  
  835. HLock(Handle(_GTERM));
  836.  
  837. { CONNECTION TOOL    }
  838. procID := FindToolID(ClassCM);
  839. IF (procID = -1) THEN
  840.     AlertUser('No connection tools found',TRUE);
  841.  
  842. sizes[cmDataIn] := kBufferSize;        { Just the data channel please    }
  843. sizes[cmDataOut] := kBufferSize;
  844. sizes[cmCntlIn] := 0;
  845. sizes[cmCntlOut] := 0;
  846. sizes[cmAttnIn] := 0;
  847. sizes[cmAttnOut] := 0;
  848.  
  849. gConn := CMNew(procID, cmData, sizes, 0, 0);
  850. IF gConn = NIL THEN
  851.     AlertUser('Can''t create a connection tool',TRUE);
  852.     
  853. HLock(Handle(gConn));
  854.  
  855. { Allocate space for the read/writes using the number    }
  856. { returned by the connection tool                        }
  857.  
  858. gBuffer := NewPtr(sizes[cmDataIn]);
  859. IF MemError <> noErr THEN
  860.     AlertUser('Out of memory, eh',TRUE);
  861.  
  862. { FILE TRANSFER TOOL    }
  863. procID := FindToolID(ClassFT);
  864. IF (procID = -1) THEN
  865.     AlertUser('No file transfer tools found',FALSE);
  866.  
  867. { No read/write proc.  Let the tool use its own        }
  868. gFT := FTNew(procID,0,@FTsendProc,@FTreceiveProc,NIL,NIL,
  869.                                 @ToolGetConnEnvirons,window,0,0);
  870. IF gFT = NIL THEN
  871.     AlertUser('Can''t create a file transfer tool',TRUE);
  872.     
  873. HLock(Handle(gFT));
  874.  
  875. gWasFT := FALSE;            { FT in progress                    }
  876. gStartFT := FALSE;            { Auto-received string found        }
  877. gFTSearchRefNum := 0;        { Clear the search refnum            }
  878.             
  879. AddFTSearch;                { Look for the auto-receive string    }
  880.  
  881. DoNewWindow := TRUE;
  882.                     
  883. END; {DoNewWindow}
  884.  
  885.  
  886.  
  887. { ******************************************************************
  888. *    Initialize        - Inits the various toolbox stuff
  889. *
  890. ********************************************************************* }
  891.  
  892. {$S Initialize}
  893. PROCEDURE Initialize;
  894.  
  895. VAR
  896. menuBar            : Handle;
  897. window            : WindowPtr;
  898. ignoreError        : OSErr;
  899. total, contig    : LongInt;
  900. ignoreResult    : BOOLEAN;
  901. event            : EventRecord;
  902. count            : INTEGER;
  903. TerraMac        : SysEnvRec;    {set up by Initialize}
  904. err                : INTEGER;
  905. i                : INTEGER;
  906.  
  907. BEGIN
  908. { Do we have Multifinder?    }
  909. gHasWaitNextEvent := TrapAvailable(_WaitNextEvent, ToolTrap);
  910. gInBackground := FALSE;
  911.  
  912. { Standard Fare        }
  913. InitGraf(@thePort);
  914. InitFonts;
  915. InitWindows;
  916. InitMenus;
  917. TEInit;
  918. InitDialogs(NIL);
  919. InitCursor;
  920.  
  921. { Bring us to the front        }
  922. FOR count := 1 TO 3 DO
  923.     ignoreResult := GetNextEvent(everyEvent, event);
  924.  
  925. { Does CommToolbox Exist    }
  926. IF NOT TrapAvailable(_CommToolboxTrap, OSTrap) THEN
  927.     AlertUser('ACK!! No CommToolbox',TRUE);
  928.  
  929. { Check for System 6.0 or better, 64K ROM    }
  930. ignoreError := SysEnvirons(kSysEnvironsVersion, TerraMac);
  931.  
  932. WITH TerraMac DO
  933.     IF (systemVersion < $0600) OR (machineType < 0) THEN 
  934.         AlertUser('Need System 6.0 or better',TRUE);
  935.  
  936. { Check various memory configs                }
  937. IF ORD(GetApplLimit) - ORD(ApplicZone) < kMinHeap THEN 
  938.     AlertUser('Out of Memory, eh',TRUE);
  939.  
  940. PurgeSpace(total, contig);
  941. IF total < kMinSpace THEN 
  942.     AlertUser('Out of Memory, eh',TRUE);
  943.  
  944. { Load up the Communications Toolbox        }
  945. { Must Initialize CRM & CTBUtilities first    }
  946. err :=     InitCTBUtilities;
  947. err :=     InitCRM;
  948.  
  949. err := InitTM;
  950. IF err = TMNoTools THEN
  951.     AlertUser('No terminal tools found',TRUE);
  952.  
  953. err :=     InitCM;    { initializes the Connection Manager }
  954. IF err = CMNoTools THEN
  955.     AlertUser('No connection tools found',TRUE);
  956.  
  957. err :=     InitFT;    { initializes the File Transfer Manager }
  958. IF err = FTNoTools THEN
  959.     AlertUser('No file transfer tools found',FALSE);
  960.     
  961. _GTERM := NIL;
  962. gConn := NIL;
  963. gFT := NIL;
  964. gFTSearchRefNum := 0;
  965.  
  966. { allocate a handle for copying text }
  967. _MYDATAHANDLE := NewHandle( CACHESIZE );
  968.  
  969. { init _BLANKLINE to all blanks }
  970. for i:= MINCACHECOL TO MAXCACHECOL DO
  971.     _BLANKLINE[i] := ' ';
  972.  
  973. IF NOT DoNewWindow THEN
  974.     AlertUser('Can''t create a session',TRUE);
  975.  
  976. menuBar := GetNewMBar(rMenuBar);        {read menus into menu bar}
  977. IF menuBar = NIL THEN 
  978.     AlertUser('Can''t get the menu bar',TRUE);
  979. SetMenuBar(menuBar);                    {install menus}
  980. DisposHandle(menuBar);
  981.  
  982. AddResMenu(GetMHandle(mApple), 'DRVR');    {add DA names to Apple menu}
  983. DrawMenuBar;
  984.  
  985. gStopped := TRUE;
  986. END; {Initialize}
  987.  
  988.  
  989. { ******************************************************************
  990. *    Terminate        - Cleans up and exits
  991. *
  992. ********************************************************************* }
  993.  
  994. {$S Main}
  995. PROCEDURE Terminate;
  996. VAR
  997. aWindow    : WindowPtr;        { the window to shut        }
  998. closed    : BOOLEAN;            { Are we done, yet            }
  999.  
  1000. BEGIN
  1001. { Close all the open windows    }
  1002. closed := TRUE;
  1003.  
  1004. aWindow := FrontWindow;    
  1005.  
  1006. REPEAT        
  1007.     IF (aWindow <> NIL) THEN
  1008.         IF IsAppWindow(aWindow) THEN
  1009.             closed := DoCloseWindow(aWindow);
  1010.             
  1011.     { Try the next window    }
  1012.     IF (aWindow <> NIL) THEN
  1013.         aWindow := WindowPtr(WindowPeek(aWindow)^.nextWindow); 
  1014.     
  1015. UNTIL (NOT closed) | (aWindow = NIL);
  1016.  
  1017. IF closed THEN
  1018.     ExitToShell;                            {exit if no cancellation}
  1019. END; {Terminate}
  1020.  
  1021.  
  1022.  
  1023. { ******************************************************************
  1024. *    AdjustMenus        - Enables & Disables items based on current state
  1025. *
  1026. ********************************************************************* }
  1027.  
  1028. {$S Main}
  1029. PROCEDURE AdjustMenus;
  1030. VAR
  1031. window            : WindowPtr;        { whose in front            }
  1032. menu            : MenuHandle;        { the menu to manipulate    }
  1033. theErr            : CMErr;
  1034. sizes            : CMBufferSizes;        { Connection tool data        }
  1035. status            : CMStatFlags;
  1036.  
  1037. BEGIN
  1038. window := FrontWindow;
  1039.  
  1040. menu := GetMHandle(mFile);
  1041. IF (menu = NIL) THEN
  1042.     AlertUser('Can''t get menu resource', TRUE);
  1043.     
  1044. IF (gConn <> NIL) THEN BEGIN
  1045.     theErr := CMStatus(gConn,sizes,status);
  1046.     IF (theErr = noErr) THEN BEGIN
  1047.         IF NOT IsDAWindow(window) THEN BEGIN
  1048.             SetItem(menu,iOpen,'Open Connection');
  1049.             SetItem(menu,iClose,'Close Connection');
  1050.             
  1051.             { Let the menu show the proper state of the union    }
  1052.             IF BAND(status, cmStatusOpen + cmStatusOpening) = 0 THEN BEGIN
  1053.                 EnableItem(menu, iOpen);
  1054.                 DisableItem(menu, iClose);
  1055.             END
  1056.             ELSE BEGIN
  1057.                 DisableItem(menu, iOpen);
  1058.                 EnableItem(menu, iClose);
  1059.             END;
  1060.             
  1061.             { Check state of the FT tool to Enable send/receive    }
  1062.             DisableItem(menu,iSendFile);
  1063.             DisableItem(menu,iReceiveFile);
  1064.             
  1065.             IF (gFT <> NIL) THEN BEGIN
  1066.                 IF BAND(gFT^^.attributes,ftSendDisable) = 0 THEN
  1067.                     EnableItem(menu,iSendFile);
  1068.                     
  1069.                 IF BAND(gFT^^.attributes,ftReceiveDisable) = 0 THEN
  1070.                     EnableItem(menu,iReceiveFile);                    
  1071.             END;
  1072.         END
  1073.         ELSE BEGIN
  1074.             { Set for desk accesories    }
  1075.             SetItem(menu,iOpen,'Open');
  1076.             SetItem(menu,iClose,'Close');
  1077.             DisableItem(menu, iOpen);
  1078.             EnableItem(menu,iClose);
  1079.             DisableItem(menu,iSendFile);
  1080.             DisableItem(menu,iReceiveFile);
  1081.         END;
  1082.         
  1083.     END; { good status    }
  1084. END; { good connection    }
  1085.  
  1086.  
  1087. menu := GetMHandle(mEdit);
  1088. IF (menu = NIL) THEN
  1089.     AlertUser('Can''t get menu resource', TRUE);
  1090.  
  1091. IF IsDAWindow(window) THEN BEGIN        { DAs might use this menu    }
  1092.     EnableItem(menu, iUndo);
  1093.     EnableItem(menu, iCut);
  1094.     EnableItem(menu, iCopy);
  1095.     EnableItem(menu, iPaste);
  1096.     EnableItem(menu, iClear);
  1097. END ELSE BEGIN                            { but we don't use it yet    }
  1098.     DisableItem(menu, iUndo);
  1099.     DisableItem(menu, iCut);
  1100.     DisableItem(menu, iCopy);
  1101.     DisableItem(menu, iClear);
  1102.     DisableItem(menu, iPaste);
  1103. END;
  1104.  
  1105. menu := GetMHandle(mSettings);
  1106. IF (menu = NIL) THEN
  1107.     AlertUser('Can''t get menu resource', TRUE);
  1108.     
  1109. IF NOT IsDAWindow(window) THEN BEGIN        { Enable if we're front    }
  1110.     EnableItem(menu, iConnection);
  1111.     EnableItem(menu, iFileTransfer);
  1112.     EnableItem(menu, iTerminal);
  1113. END ELSE BEGIN
  1114.     DisableItem(menu, iConnection);
  1115.     DisableItem(menu, iFileTransfer);
  1116.     DisableItem(menu, iTerminal);
  1117. END;
  1118.  
  1119. END; {AdjustMenus}
  1120.  
  1121.  
  1122. { ******************************************************************
  1123. *    DoToolMenu        - Tries to give the menu to the tool
  1124. *
  1125. *        menuID        - the menu info from DoMenuCommand
  1126. *        menuItem
  1127. *
  1128. *        returns        - TRUE if a tool handled the menu
  1129. *
  1130. ********************************************************************* }
  1131. {$S Main}
  1132. FUNCTION DoToolMenu(menuID, menuItem: INTEGER): BOOLEAN;
  1133. BEGIN
  1134. DoToolMenu := FALSE;
  1135.  
  1136. IF _GTERM <> NIL THEN
  1137.     IF TMMenu(_GTERM, menuID, menuItem) THEN BEGIN
  1138.         DoToolMenu := TRUE;
  1139.         Exit(DoToolMenu);
  1140.     END;
  1141.  
  1142. IF gConn <> NIL THEN
  1143.     IF CMMenu(gConn, menuID, menuItem) THEN BEGIN
  1144.         DoToolMenu := TRUE;
  1145.         Exit(DoToolMenu);
  1146.     END;
  1147.  
  1148. IF gFT <> NIL THEN
  1149.     IF FTMenu(gFT, menuID, menuItem) THEN
  1150.         DoToolMenu := TRUE;
  1151.         
  1152. END; {DoToolMenu}
  1153.  
  1154.  
  1155.  
  1156. { ******************************************************************
  1157. *    DoMenuCommand    - Executes a menu command
  1158. *
  1159. *        menuResult    - the menu id and item number
  1160. *
  1161. ********************************************************************* }
  1162.  
  1163. {$S Main}
  1164. PROCEDURE DoMenuCommand(menuResult: LONGINT);
  1165. VAR
  1166. menuID            : INTEGER;        { resource ID of the selected menu    }
  1167. menuItem        : INTEGER;        { item number of the selected menu    }
  1168. itemHit            : INTEGER;        { for the alert                        }
  1169. daName            : Str255;        { for opening desk accesories        }
  1170. daRefNum        : INTEGER;
  1171. handledByDA        : BOOLEAN;        { DA edit menu handling                }
  1172. ignore            : BOOLEAN;        
  1173. where            : Point;        { For choose dialog                    }
  1174. result            : INTEGER;
  1175.  
  1176. BEGIN
  1177. menuID := HiWrd(menuResult);    {use built-ins (for efficiency)...}
  1178. menuItem := LoWrd(menuResult);    {to get menu item number and menu number}
  1179.  
  1180. { First see if the menu belonged to a tool    }
  1181.     
  1182. IF NOT DoToolMenu(menuID,menuItem) THEN
  1183.     CASE menuID OF
  1184.         mApple:
  1185.             CASE menuItem OF
  1186.                 iAbout:                {bring up alert for About}
  1187.                     itemHit := Alert(rAboutAlert, NIL);
  1188.                 OTHERWISE BEGIN        {all non-About items in this menu are DAs}
  1189.                     GetItem(GetMHandle(mApple), menuItem, daName);
  1190.                     daRefNum := OpenDeskAcc(daName);
  1191.                 END;
  1192.             END; { case    }
  1193.             
  1194.         mFile:
  1195.             CASE menuItem OF
  1196.                 iOpen:
  1197.                     IF NOT IsDAWindow(FrontWindow) THEN
  1198.                         OpenConnection;
  1199.                     
  1200.                 iClose:
  1201.                     IF IsDAWindow(FrontWindow) THEN
  1202.                         ignore := DoCloseWindow(FrontWindow)
  1203.                     ELSE
  1204.                         CloseConnection;
  1205.                         
  1206.                 iSendFile:
  1207.                     IF NOT IsDAWindow(FrontWindow) THEN
  1208.                         DoSend;
  1209.                     
  1210.                 iReceiveFile:
  1211.                     IF NOT IsDAWindow(FrontWindow) THEN
  1212.                         DoReceive;
  1213.                         
  1214.                 iQuit:
  1215.                     Terminate;
  1216.             END; { case    }
  1217.             
  1218.         mEdit:                        {call SystemEdit for DA editing & MultiFinder}
  1219.             handledByDA := SystemEdit(menuItem-1);    {since we don't do any editing}
  1220.             
  1221.         mSettings:
  1222.             CASE menuItem OF
  1223.                 iConnection:
  1224.                     IF gConn <> NIL THEN BEGIN
  1225.                         HUnlock(Handle(gConn));
  1226.                         
  1227.                         SetPt(where,10,40);
  1228.                         result := CMChoose(gConn, where, NIL);
  1229.                         
  1230.                         CASE result OF
  1231.                             chooseDisaster,
  1232.                             chooseFailed:
  1233.                                 AlertUser('Connection choose failed',(result = chooseDisaster));
  1234.                             chooseOKMajor:
  1235.                                 AddFTSearch;
  1236.                         END;
  1237.                         
  1238.                         HLock(Handle(gConn));
  1239.                     END; { good conn    }
  1240.                     
  1241.                 iFileTransfer:
  1242.                     IF (gFT <> NIL) THEN BEGIN
  1243.                         HUnlock(Handle(gFT));
  1244.                         
  1245.                         SetPt(where,10,40);
  1246.                         result := FTChoose(gFT, where, NIL);
  1247.                         
  1248.                         CASE result OF
  1249.                             chooseDisaster,
  1250.                             chooseFailed:
  1251.                                 AlertUser('File Transfer choose failed',
  1252.                                                         (result = chooseDisaster));
  1253.                             chooseOKMinor,
  1254.                             chooseOKMajor: BEGIN
  1255.                                 { Get rid of the old search            }
  1256.                                 IF (gFTSearchRefNum <> 0) AND (gConn <> NIL) THEN
  1257.                                     CMRemoveSearch(gConn,gFTSearchRefNum);
  1258.                                 gFTSearchRefNum := 0;
  1259.                                 
  1260.                                 AddFTSearch;    { Add the new FT tool search    }
  1261.                             END;
  1262.                         END;
  1263.                         
  1264.                         HLock(Handle(gFT));
  1265.                     END; { good ft    }
  1266.                     
  1267.                 iTerminal: 
  1268.                     IF (_GTERM <> NIL) THEN BEGIN
  1269.                         HLock(Handle(_GTERM));
  1270.                         
  1271.                         SetPt(where,10,40);
  1272.                         result := TMChoose(_GTERM, where, NIL);
  1273.                         
  1274.                         IF (result < 0) THEN
  1275.                             AlertUser('Terminal choose failed',(result = chooseDisaster))
  1276.                         ELSE IF (result = chooseOKMinor) OR (result = chooseOKMajor) THEN
  1277.                             { validate termenvironment if anything has changed in TMChoose }
  1278.                             CheckTermEnv( TRUE );
  1279.                     
  1280.                         HUnlock(Handle(_GTERM));
  1281.                     END; { good term    }
  1282.                     
  1283.             END; { case    menuitem    }
  1284.                 
  1285.     END; { case menuid    }
  1286.  
  1287. HiliteMenu(0);                    {unhighlight what MenuSelect (or MenuKey) hilited}
  1288. END; {DoMenuCommand}
  1289.  
  1290.  
  1291. { ******************************************************************
  1292. *    DoUpdate    - Updates the window
  1293. *
  1294. *        window    - target of teh update
  1295. *
  1296. ********************************************************************* }
  1297. {$S Main}
  1298. PROCEDURE DoUpdate(window: WindowPtr);
  1299. VAR
  1300. savedClip    : RgnHandle;        { saved info for reset later    }
  1301. savedPort    : GrafPtr;
  1302.  
  1303. BEGIN
  1304. IF IsAppWindow(window) THEN BEGIN
  1305.     GetPort(savedPort);
  1306.     SetPort(window);
  1307.     
  1308.     { Clip to the window content    }
  1309.     savedClip := NewRgn;
  1310.     GetClip(savedClip);
  1311.     ClipRect(window^.PORTRECT);
  1312.     
  1313.     BeginUpdate(window);
  1314.         { update the cache area }
  1315.         
  1316.         { update the cache area }
  1317.         UpdateCache( window^.visRgn );
  1318.             
  1319.         IF _GTERM <> NIL THEN    { Update the terminal tool        }
  1320.             TMUpdate(_GTERM, window^.visRgn);
  1321.             
  1322.         { update the scroll bar area }
  1323.         DrawControls(window);
  1324.         { update the grow box }
  1325.         DrawGrowIcon( window );
  1326.     EndUpdate(window);
  1327.     
  1328.     SetClip(savedClip);
  1329.     DisposeRgn(savedClip);
  1330.     
  1331.     SetPort(savedPort);
  1332. END;
  1333. END; {DoUpdate}
  1334.  
  1335.  
  1336. { ******************************************************************
  1337. *    DoResume    - Suspends/Resumes the window
  1338. *
  1339. *        becomingActive    - Resume or Suspend
  1340. *
  1341. ********************************************************************* }
  1342.  
  1343. {$S Main}
  1344. PROCEDURE DoResume(becomingActive: BOOLEAN);
  1345. VAR
  1346. theWindow    : WindowPtr;
  1347. savedPort    : GrafPtr;
  1348.  
  1349. BEGIN
  1350. { Since the front window could be a tool window, we need    }
  1351. { to find the app window by walking the list so we can        }
  1352. { send resume messages to the tools                            }
  1353.  
  1354. GetPort(savedPort);
  1355.  
  1356. theWindow := FrontWindow;
  1357.  
  1358. WHILE (theWindow <> NIL) DO BEGIN
  1359.     IF IsAppWindow(theWindow) THEN BEGIN
  1360.         SetPort(theWindow);
  1361.     
  1362.         CacheActivate( theWindow, becomingActive );
  1363.         { Tools need to adjust their menus, text selection, etc    }            
  1364.         IF _GTERM <> NIL THEN
  1365.             TMResume(_GTERM, becomingActive);
  1366.         
  1367.         IF gConn <> NIL THEN
  1368.             CMResume(gConn, becomingActive);
  1369.     
  1370.         IF gFT <> NIL THEN
  1371.             FTResume(gFT, becomingActive);
  1372.     END; { app window    }
  1373.     
  1374.     { Try the next window    }
  1375.     theWindow := WindowPtr(WindowPeek(theWindow)^.nextWindow);
  1376. END;
  1377.  
  1378. SetPort(savedPort);
  1379.  
  1380. END; {DoResume}
  1381.  
  1382.  
  1383. { ******************************************************************
  1384. *    DoActivate    - (De)Activates the window
  1385. *
  1386. *        window            - target of the update
  1387. *        becomingActive    - Activate or Deactivate
  1388. *
  1389. ********************************************************************* }
  1390.  
  1391. {$S Main}
  1392. PROCEDURE DoActivate(window: WindowPtr; becomingActive: BOOLEAN);
  1393. BEGIN
  1394. IF IsAppWindow(window) THEN BEGIN
  1395.     SetPort(window);
  1396.  
  1397.     { adjust the selection in the cache area }
  1398.     CacheActivate( window, becomingActive );
  1399.     { Tools need to adjust their menus, text selection, etc    }            
  1400.     IF _GTERM <> NIL THEN
  1401.         TMActivate(_GTERM, becomingActive);
  1402.     
  1403.     IF gConn <> NIL THEN
  1404.         CMActivate(gConn, becomingActive);
  1405.  
  1406.     IF gFT <> NIL THEN
  1407.         FTActivate(gFT, becomingActive);
  1408. END;
  1409.  
  1410. END; {DoActivate}
  1411.  
  1412.  
  1413. { ******************************************************************
  1414. *    AdjustCursor    - Updates mouse cursor depending on location
  1415. *
  1416. *        mouse        - the location of the mouse (global coords)
  1417. *
  1418. ********************************************************************* }
  1419. {$S Main}
  1420. PROCEDURE AdjustCursor(mouse: Point);
  1421. VAR
  1422. window                : WindowPtr;
  1423.  
  1424. BEGIN
  1425. window := FrontWindow;        { Adjust only if front            }
  1426.  
  1427. IF (NOT gInBackground) AND (IsAppWindow(window)) THEN BEGIN
  1428.     GlobalToLocal(mouse);
  1429.     
  1430.     { If it's outside the content, set to arrow        }
  1431.     { otherwise the terminal tool will  handle it    }
  1432.     
  1433.     IF (_GTERM <> NIL) THEN
  1434.         IF NOT PtInRect(mouse,_GTERM^^.viewRect) THEN
  1435.             InitCursor;
  1436.             
  1437. END; { app window    }
  1438.  
  1439. END; {AdjustCursor}
  1440.  
  1441.  
  1442. { ******************************************************************
  1443. *    DoToolEvent        - Tries to pass the event to a tool if the 
  1444. *                    window is a tool window
  1445. *
  1446. *        event        - the event received
  1447. *
  1448. *        returns        - True if the tool handled it
  1449. *
  1450. ********************************************************************* }
  1451. {$S Main}
  1452. FUNCTION DoToolEvent(event: EventRecord; window: WindowPtr): BOOLEAN;
  1453. BEGIN
  1454. IF (window <> NIL) THEN BEGIN
  1455.     DoToolEvent := TRUE;
  1456.     
  1457.     IF (gFT <> NIL) AND 
  1458.             (gFT = FTHandle(GetWRefCon(window))) THEN
  1459.         FTEvent(gFT, event)
  1460.     ELSE IF (gConn <> NIL) AND 
  1461.             (gConn = ConnHandle(GetWRefCon(window))) THEN
  1462.         CMEvent(gConn, event)
  1463.     ELSE IF (_GTERM <> NIL) AND 
  1464.             (_GTERM = TermHandle(GetWRefCon(window))) THEN
  1465.         TMEvent(_GTERM, event)
  1466.     ELSE
  1467.         DoToolEvent := FALSE;
  1468. END
  1469. ELSE
  1470.     DoToolEvent := FALSE;
  1471.     
  1472. END; {DoToolEvent}
  1473.  
  1474.  
  1475.  
  1476. { ******************************************************************
  1477. *    DoEvent    - Updates mouse cursor depending on location
  1478. *
  1479. *        event    - the event to handle
  1480. *
  1481. ********************************************************************* }
  1482. {$S Main}
  1483. PROCEDURE DoEvent(event: EventRecord);
  1484. VAR
  1485. part,                            { where the mouse click was    }
  1486. err            : INTEGER;
  1487. window        : WindowPtr;        { the click's window        }
  1488. key            : CHAR;                { the letter typed            }
  1489. aPoint        : Point;            { for the dialog top left    }
  1490. result        : LONGINT;            { result from MenuKey        }
  1491. processed    : BOOLEAN;            { Did the App handle it        }
  1492. locmouse    : Point;            { local mouse location      }
  1493.  
  1494. BEGIN
  1495. CASE event.what OF
  1496.     mouseDown: BEGIN
  1497.         part := FindWindow(event.where, window);
  1498.  
  1499.         CASE part OF
  1500.             inMenuBar: BEGIN            {process the menu command}
  1501.                 AdjustMenus;
  1502.                 DoMenuCommand(MenuSelect(event.where));
  1503.             END;
  1504.             
  1505.             inSysWindow:                {let the system handle the mouseDown}
  1506.                 SystemClick(event, window);
  1507.                 
  1508.             inContent:
  1509.                 { The terminal tool needs to handle selections    }
  1510.                 IF NOT DoToolEvent(event,window) THEN BEGIN
  1511.                     IF window <> FrontWindow THEN
  1512.                         SelectWindow(window)
  1513.                     ELSE IF (_GTERM <> NIL) THEN
  1514.                         BEGIN
  1515.                             { surfer 1.1 changes starts }
  1516.                             HandleMouseDown( window, event );
  1517.                             { surfer 1.1 changes ends }
  1518.                         END;
  1519.                 END;
  1520.                     
  1521.             inDrag:        {pass screenBits.bounds to get all gDevices}
  1522.                 IF NOT DoToolEvent(event,window) THEN
  1523.                     DragWindow(window, event.where, screenBits.bounds);
  1524.                 
  1525.             { surfer 1.1 changes starts }
  1526.             inGrow:    
  1527.                     IF NOT DoToolEvent(event,window) THEN
  1528.                             DoSizeWindow( window, event);
  1529.  
  1530.             { surfer 1.1 changes ends }
  1531.             
  1532.             inZoomIn, inZoomOut,
  1533.             inGoAway:
  1534.                 IF DoToolEvent(event,window) THEN ;
  1535.         END; { Case Mousedown    }
  1536.             
  1537.     END; { Mousedown    }
  1538.     
  1539.     keyDown, autoKey: BEGIN                {check for menukey equivalents}
  1540.         window := FrontWindow;
  1541.         
  1542.         { Get the key    }
  1543.         key := CHR(BAnd(event.message, charCodeMask));
  1544.         processed := FALSE;
  1545.         
  1546.         { The terminal tool might be mapping the cmd key     }
  1547.         { so if menukey fails, send it to the tool            }
  1548.         
  1549.         IF BAND(event.modifiers, cmdKey) <> 0 THEN BEGIN
  1550.             AdjustMenus;            {enable/disable/check menu items properly}
  1551.             result := MenuKey(key);
  1552.             IF result <> 0 THEN BEGIN
  1553.                 processed := TRUE;
  1554.                 DoMenuCommand(result)
  1555.             END;
  1556.         END;
  1557.         
  1558.         IF (_GTERM <> NIL) AND NOT processed THEN
  1559.             IF NOT DoToolEvent(event,window) THEN
  1560.             BEGIN
  1561.                 DeSelection;
  1562.                 TMKey(_GTERM, event);    
  1563.                 CheckTermEnv( FALSE );
  1564.             END;
  1565.     END;
  1566.     
  1567.     activateEvt: BEGIN
  1568.         window := WindowPtr(event.message);
  1569.         
  1570.         IF NOT DoToolEvent(event,window) THEN
  1571.             DoActivate(window, BAND(event.modifiers, activeFlag) <> 0);
  1572.     END;
  1573.     
  1574.     updateEvt: BEGIN
  1575.         window := WindowPtr(event.message);
  1576.         
  1577.         IF NOT DoToolEvent(event,window) THEN
  1578.             DoUpdate(window);
  1579.     END;
  1580.     
  1581.     diskEvt:
  1582.         IF HiWrd(event.message) <> noErr THEN BEGIN
  1583.             SetPt(aPoint, kDILeft, kDITop);
  1584.             err := DIBadMount(aPoint, event.message);
  1585.         END;
  1586.         
  1587.     kOSEvent:
  1588.         { Send to frontmost tool window AND all tools    }
  1589.         { as this is an application-wide event            }
  1590.         
  1591.         CASE BAnd(BRotL(event.message, 8),$FF) OF    {high byte of message}
  1592.             kSuspendResumeMessage: BEGIN
  1593.                 IF NOT DoToolEvent(event,FrontWindow) THEN
  1594.                     ;
  1595.                     
  1596.                 gInBackground := BAnd(event.message, kResumeMask) = 0;
  1597.                 DoResume(NOT gInBackground);
  1598.             END;
  1599.         END;
  1600. END;
  1601. END; {DoEvent}
  1602.  
  1603.  
  1604. { ******************************************************************
  1605. *    DoIdle    - Idles all the tools
  1606. *
  1607. ********************************************************************* }
  1608. {$S Main}
  1609. PROCEDURE DoIdle;
  1610. VAR
  1611. theWindow     : WindowPtr;                { The target to idle        }
  1612. doFT         : BOOLEAN;                    { route data to FT Tool        }
  1613. doTM         : BOOLEAN;                    { route data to Term Tool    }
  1614. savedPort    : GrafPtr;                    { for later reset            }
  1615.  
  1616. BEGIN
  1617. GetPort(savedPort);                        { Save for later            }
  1618. theWindow := FrontWindow;                { Gimme the first one        }
  1619.  
  1620. { Give idle time for the window    }
  1621. WHILE (theWindow <> NIL) DO BEGIN
  1622.     IF IsAppWindow(theWindow) THEN BEGIN
  1623.         SetPort(theWindow);                    { Focus on it                }
  1624.         
  1625.         IF gConn <> NIL THEN            { Give time to the connection    }
  1626.             CMIdle(gConn);
  1627.             
  1628.         doFT := FALSE;                    { Send data to FT tool            }
  1629.         doTM := TRUE;                    { Send data to terminal tool    }
  1630.         
  1631.         IF gFT <> NIL THEN BEGIN
  1632.             { Is there a file transfer in progress ??    }
  1633.             IF BAND(gFT^^.flags, ftIsFTMode) <> 0 THEN BEGIN
  1634.                 doFT := TRUE;
  1635.                 gWasFT := TRUE;
  1636.                 
  1637.                 { If the FT tool uses my connection then    }
  1638.                 { don't route data to the terminal tool        }
  1639.                 
  1640.                 IF BAND(gFT^^.attributes, ftSameCircuit) <> 0 THEN 
  1641.                     doTM := FALSE;
  1642.             END    { In progress    }
  1643.             
  1644.             ELSE BEGIN
  1645.                 IF gWasFT THEN BEGIN
  1646.                     { FT no longer in progress        }
  1647.                     gWasFT := FALSE;
  1648.                     
  1649.                     { FT tool will alert the user    }
  1650.                     IF BAND(gFT^^.flags, FTSucc) = 0 THEN
  1651.                         ;
  1652.                     
  1653.                     { The old search was removed for the transfer    }
  1654.                     { so we need to re-add it here                    }
  1655.                     AddFTSearch;
  1656.                 END;
  1657.                                     
  1658.                 { AutoReceive string was received ?    }
  1659.                 IF gStartFT THEN
  1660.                     DoReceive;
  1661.             END; { No FT in progress    }
  1662.             
  1663.             IF doFT THEN            { Give time to FT tool                }
  1664.                 FTExec(gFT);
  1665.             
  1666.         END; { Good FT Handle    }
  1667.                             
  1668.         IF _GTERM <> NIL THEN BEGIN
  1669.             { Send data to terminal    }
  1670.             IF doTM THEN BEGIN
  1671.                 TMIdle(_GTERM);                { So it can blink its cursor, etc    }
  1672.                 
  1673.                 TermRecvProc;                { Send Data to the terminal            }
  1674.             END; { Send data to terminal    }
  1675.             
  1676.         END; { Good Terminal    }
  1677.         
  1678.     END; { App Window    }
  1679.     
  1680.     { Try the next window    }
  1681.     theWindow := WindowPtr(WindowPeek(theWindow)^.nextWindow);
  1682.         
  1683. END; { while each window    }
  1684.         
  1685. SetPort(savedPort);                        { Back to the way it was        }
  1686.     
  1687. END; { DoIdle    }
  1688.  
  1689.  
  1690. { ******************************************************************
  1691. *    EventLoop    - The main event loop 
  1692. *
  1693. ********************************************************************* }
  1694. {$S Main}
  1695. PROCEDURE EventLoop;
  1696. VAR
  1697. gotEvent    : BOOLEAN;
  1698. event        : EventRecord;
  1699.  
  1700. BEGIN
  1701. REPEAT
  1702.     DoIdle;
  1703.     
  1704.     IF gHasWaitNextEvent THEN     { put us 'asleep' forever under MultiFinder    }
  1705.         gotEvent := WaitNextEvent(everyEvent, event, 0, NIL)
  1706.     ELSE BEGIN
  1707.         SystemTask;                { must be called if using GetNextEvent        }
  1708.         gotEvent := GetNextEvent(everyEvent, event);
  1709.     END;
  1710.     
  1711.     IF gotEvent THEN BEGIN
  1712.         AdjustCursor(event.where);             {make sure we have the right cursor}
  1713.         DoEvent(event);
  1714.     END;
  1715.     
  1716.     AdjustCursor(event.where);
  1717. UNTIL FALSE;                    {loop forever; we quit through an ExitToShell}
  1718. END; {EventLoop}
  1719.  
  1720.  
  1721. PROCEDURE _DataInit; EXTERNAL;
  1722.  
  1723.  
  1724. {$S Main}
  1725. BEGIN
  1726. UnloadSeg(@_DataInit);    { note that _DataInit must not be in Main!            }
  1727.      
  1728. MaxApplZone;            { expand the heap so code segments load at the top    }
  1729.  
  1730. Initialize;                { initialize the program                            }
  1731. UnloadSeg(@Initialize);    { note that Initialize must not be in Main!            }
  1732.  
  1733. EventLoop;                { call the main event loop                            }
  1734. END.
  1735.